
const ENUM = {
    factoryService: {
        发布订阅服务: 'PUB_SUB',
        字典: 'Dictionary',
        会议: 'Conference',
        状态服务: 'State',
    },
    conferenceState: {
        '200': '会议成功',
        '201': '让上一位重新发言,然后我再发言',
        '202': '禁言下一位',
        '203': '会议提前结束',
        '204': '以下自定义',

        '210': '以下保留',

        '300': '会议失败',
        '301': '会议未准备',
        '302': '会议被中止',
        '303': '保留',
        '304': '以下自定义',

        '310': '以下保留',

        '500': '未知异常',
    },
};

(function (global, debug) {
    const CACHE = {
        DATA: {},
        //CACHE_CLEANERS: [function () { CACHE.DATA = {} }],
        //ADD_CLEANER(CLEANER) { this.CACHE_CLEANERS.push(CLEANER) },
        //CLEAR() { this.CACHE_CLEANERS.forEach(async clear => clear()); },
        useCache(name) {
            return this.DATA[name] = this.DATA[name] || {};
        }
    };
    const SETTINGS = {
        UID: 0,
        primitiveTypes: ['string', 'number', 'boolean', 'symbol'],
    };
    const Core = {
        utils: {
            guid() { return SETTINGS.UID++; },
            grantUid(obj) {
                let uid = this.guid();
                Object.defineProperty(obj, '_uid_', {
                    value: uid
                });
                return uid;
            },
            isPrimitive(value) {
                return SETTINGS.primitiveTypes.includes(typeof value);
            },
            isObject(obj) {
                return obj !== null && typeof obj === 'object'
            },
            isFunc(obj) {
                return typeof obj === 'function';
            },
            pathData(dataSource, path, delimiter = '.') {
                let data = dataSource;
                return path.split(delimiter).map(prop => {
                    let obj = data;
                    data = data[prop];
                    return [obj, prop, data];
                });
            },

            //clearCache() {
            //    CACHE.CLEAR();
            //},
            useCache(cacheName) {
                return CACHE.useCache(cacheName);
            },
            factory(name, ...args) {
                return FACTORY.built(name, ...args)
            }
        },
    };
    const FACTORY = {
        built(name, ...args) {
            return this[name](...args);
        },
        PROTO: {
            PUB_SUB: {
                subscribe(topic, group, subscriber) {
                    let topics = this.data;
                    if (!topics.has(topic)) topics.set(topic, new Map());
                    let groups = topics.get(topic);
                    if (!groups.has(group)) groups.set(group, new Set())
                    let subscribers = groups.get(group);
                    subscribers.add(subscriber);
                },
                notify(topic, group, info, unSubscribe) {
                    let topics = this.data;
                    if (!topics.has(topic)) return;
                    let groups = topics.get(topic);
                    if (group && !groups.has(group)) return;
                    if (group) {
                        groups = [groups.get(group)];
                    }
                    groups.forEach(subscribers => subscribers.forEach(subscriber => {
                        subscriber.see(info, group, topic);
                        if (unSubscribe) subscribers.delete(subscriber);
                    }));
                },
                unSubscribe(topic, group, subscriber) {
                    let topics = this.data;
                    if (!topics.has(topic)) return;
                    let groups = topics.get(topic);
                    if (!groups.has(group)) return;
                    groups.get(group).delete(subscriber);
                },
                clear(topic, group) {
                    let topics = this.data;
                    if (!topics.has(topic)) return;
                    if (!group) return topics.delete(topic);
                    topics.get(topic).delete(group);
                },
                dispose() {
                    this.data.clear();
                }
            },
            Conference: {
                create(topic) {
                    let conferee = {
                        say: async function (pipe) {
                            pipe.success = true;
                            try {
                                await this.next.say(pipe);
                            } catch (error) {
                                pipe.success = false;
                                pipe.error = error;
                            }
                            return pipe;
                        }
                    };
                    this.data.set(topic, conferee);
                    return {
                        add(next) {
                            conferee = conferee.next = next;
                            return this;
                        }
                    };
                },
                convoke: async function (topic, pipe) {
                    let topics = this.data;
                    if (!topics.has(topic)) throw ENUM.conferenceState[301];
                    return topics.get(topic).say(pipe);
                },
            },
            Dictionary: {
                check(value) {
                    return true;
                },
                set(obj, prop, value) {
                    if (this.check(value, prop)) {
                        obj.set(prop, value);
                        return true;
                    }
                    console.error(`(字典)数据非法:${value}不符合约束`);
                    return false;
                },
                get(obj, prop, receiver) {
                    if (obj.has(prop)) return obj.get(prop);
                    let fn = obj[prop];
                    if (fn && fn instanceof Function) return fn.bind(obj);
                    if (prop === '$0') return obj;
                }
            },
            State: {

            }
        },
        /**发布订阅服务 */
        PUB_SUB() {
            let o = Object.create(this.PROTO.PUB_SUB);
            let uid = Core.utils.grantUid(o);
            let cache = CACHE.useCache('PUB_SUB');
            o.data = cache[uid] = new Map();
            return o;
        },
        Conference() {
            let o = Object.create(this.PROTO.Conference);
            let uid = Core.utils.grantUid(o);
            let cache = CACHE.useCache('Conference');
            o.data = cache[uid] = new Map();
            return o;
        },
        Dictionary(checker) {
            let handler = Object.create(this.PROTO.Dictionary);
            if (checker) handler.check = checker;
            return new Proxy(new Map(), handler);
        },
        State() {
            let o = Object.create(this.PROTO.State);
            let uid = Core.utils.grantUid(o);
            let cache = CACHE.useCache('State');
            o.data = cache[uid] = new Map();
            return o;
        },
    };
    SETTINGS.DI = FACTORY.built(ENUM.factoryService.字典);

    Object.assign(global, {
        inject(name, service) {
            SETTINGS.DI[name] = service;
        },
        require(name) {
            let service = SETTINGS.DI[name];
            if (service) return service;
            throw new Error('未注册的服务：' + name);
        },
        using(...names) {
            return names.map(name => this.require(name));
        },
        //    registerCacheCleaner(Cleaner) {
        //        CACHE.ADD_CLEANER(Cleaner);
        //    },
    });

    Core.pub_sub = FACTORY.built(ENUM.factoryService.发布订阅服务);
    Core.conference = FACTORY.built(ENUM.factoryService.会议);
    inject('core', Core);
    inject('extensions', []);
})(globalThis);

(function () {
    const extensions = require('extensions');
    /** @type { HTMLElement }*/
    Object.assign(HTMLElement.prototype, {
        /**从当前元素开始，向上冒泡，直到指定的祖先元素（不包含），每个元素都执行一次回调，如果回调返回true，则终止冒泡。
         * @this {Element}
         * @param {(el:Element)=>boolean} callback
         * @param {Element} parent
         */
        bubbleCall(callback, parent = document.body) {
            if (this === parent || callback(this)) return this;
            this.parentElement.bubbleCall(callback, parent);
        },
        /**
         * 对自身或最近的祖先元素执行回调，并返回回调结果。
         * @this {Element}
         * @param {(el:Element)=>boolean} predict
         * @param {Function} callback
         * @param {Element} parent
         */
        onClosest(predict, callback, parent = document) {
            if (predict(this)) return callback(this);
            if (this !== parent && this.parentElement) this.parentElement.onClosest(predict, callback, parent)
        },
        /**
         * 向上找到第一个符合要求的指定的属性的值，到指定的父元素为止，包含父元素。
         * @this {Element}
         * @param {string} key
         * @param {(keyResult)=>boolean} [keyChecker] 判断找到的值是否符合要求,不符将继续找下一个。
         * @param {Element} [parent]
         */
        key(key, keyChecker, parent = document) {
            if (!this.parentElement) return;
            let v = this.parentElement[key];
            if (v !== undefined && v !== null && (!keyChecker || keyChecker(v))) return v;
            if (this.parentElement !== parent) return this.parentElement.key(key, keyChecker, parent);
        },
    });
    const EVENT = {
            eventOption: {
                'view': globalThis,
                'bubbles': true,
                'cancelable': true
            },
            /**
             * 将一个符合标准的选择器解析为一个[type,pattern]形式的数组，以配合与Element_MATCHER的使用。
             * @param {string} selector CSS选择器形式的字符串 例如：'#bar','.foo','[baz=bar|foo]'等
             * @returns {[type:string,pattern:string]}
             */
            SELECTOR_PARSE(selector) {
                let pattern = selector.trim();
                let sType = pattern[0];
                if (sType === "[") {
                    sType = pattern.includes('=')
                        ? pattern.includes('|')
                            ? '|=' : '='
                        : "[]";
                    pattern = pattern.substring(1, pattern.length - 1);
                }
                else if ('.#'.includes(sType)) pattern = pattern.substring(1);
                else sType = '';
                return [sType, pattern];
            },
            /** 用于匹配元素的路由表*/
            Element_MATCHER: {
                /**
                 * 
                 * @param {Element} el
                 * @param {[type:''|'.'|'#'|'[]'|'='|'|=',pattern:string]} matcher
                 */
                Match(el, matcher) {
                    let [type, pattern] = matcher;
                    return this[type](el, pattern);
                },
                /**
                 * 元素匹配
                 * @param {Element} el
                 * @param {string} pattern 例如：'body'
                 */
                ''(el, pattern) {
                    return el.tagName === pattern.toUpperCase()
                },
                /**
                 * id匹配
                 * @param {Element} el
                 * @param {string} pattern 例如: 'rootId'
                 */
                "#"(el, pattern) {
                    return el.id === pattern
                },
                /**
                 * class匹配
                 * @param {Element} el
                 * @param {string} pattern 例如: 'btn'
                 */
                "."(el, pattern) {
                    return el.classList.contains(pattern)
                },
                /**
                 * 特性匹配
                 * @param {Element} el
                 * @param {string} pattern 例如: 'name'
                 */
                "[]"(el, pattern) {
                    return el.hasAttribute(pattern)
                },
                /**
                 * 特性匹配
                 * @param {Element} el
                 * @param {string} pattern 例如: 'name=mainPage'
                 */
                "="(el, pattern) {
                    let [attr, value] = pattern.split('=');
                    return el.getAttribute(attr) === value;
                },
                /**
                 * 特性匹配
                 * @param {Element} el
                 * @param {string} pattern 例如: 'name=head|top'
                 */
                "|="(el, pattern) {
                    let [attr, values] = pattern.split('=');
                    attr = el.getAttribute(attr);
                    values = values.split('|');
                    return values.includes(attr);
                },
                "&="() {//仅class

                }
            },
            /**
            * 在指定元素上代理事件
            * @param {Element} el 进行事件代理的元素，可监听对象
            * @param {string} eventType 事件类型 例如：'click','input','change'等
            * @param {[[type:string,pattern:string][],callback:Function][]} selectorGroup_callbacks 用于匹配元素
            * @param {[]} args
            */
            addEventListener(el, eventType, selectorGroup_callbacks, args) {
                let that = this;
                el.addEventListener(eventType, function (e) {
                    e.target.bubbleCall(node => {
                        let cancelBubble = false;
                        selectorGroup_callbacks.some(selectorGroup_callback => {
                            let [type_patterns, callback] = selectorGroup_callback;
                            if (type_patterns.some(type_pattern => that.Element_MATCHER.Match(node, type_pattern))) {
                                cancelBubble = !callback.call(node, e, ...args);
                                return true;
                            }
                        });
                        return cancelBubble;
                    }, el)
                });
            },
            /**
             * 在指定元素上代理事件, 是对addEventListener的一次包装
             * @param {Element} el 进行事件代理的元素，可监听对象
             * @param {string} eventType 事件类型 例如：'click','input','change'等
             * @param {{selectors1:Function,selectors2:Function}} eventsObj
             * @param {...any} args
             */
            on(el, eventType, eventsObj, ...args) {
                const cache = Object.keys(eventsObj).map(selectors => {
                    const type_patterns = selectors.split(',').map(selector => this.SELECTOR_PARSE(selector));
                    return [type_patterns, eventsObj[selectors]]
                });
                this.addEventListener(el, eventType, cache, args);
            },
            /**
             * 在指定元素上代理事件, 是对ON的一次包装
             * @param {Element} el 进行事件代理的元素，可监听对象
             * @param {{click:{'[name=body|main]':Function,'#body,.body':Function},input:{}} eventsObj
             * @param {...any} args
             */
            listen(el, eventsObj, ...args) {
                Object.entries(eventsObj).forEach(eventType_eventObj => {
                    const [eventType, eventObj] = eventType_eventObj;
                    this.on(el, eventType, eventObj, ...args);
                });
            },
            /**
             * 在指定元素上代理事件, 是对addEventListener的一次包装
             * @param {Element} el 进行事件代理的元素，可监听对象
             * @param {string} selectorGroup 用于匹配子元素的选择器，多个选择器可用','分割
             * @param {{click:Function,input:Function}} eventsObj
             * @param {...any} args
             */
            addEvents(el, selectorGroup, eventsObj, ...args) {
                const type_patterns = selectorGroup.split(',').map(selector => this.SELECTOR_PARSE(selector));
                Object.keys(eventsObj).forEach(eventType => {
                    let callback = eventsObj[eventType];
                    this.addEventListener(el, eventType, [[type_patterns, callback]], args)
                });
            },
        }
    extensions.push({
            click(...args) {
                let event = new MouseEvent('click', EVENT.eventOption);
                event.args = args;
                this.el.dispatchEvent(event);
            },
            trigger(eType, ...args) {
                let event = new CustomEvent(eType, EVENT.eventOption);
                event.args = args;
                this.el.dispatchEvent(event);
            },
            listen(eventsObj, ...args) {
                EVENT.listen(this.el, eventsObj, ...args);
            },
            addEvents(el, selectorGroup, eventsObj, ...args) {
                EVENT.addEvents(this.el, selectorGroup, eventsObj, ...args);
            }
    })
})();

(function () {
    const { conference, utils, pub_sub } = require('core');
    const cache = {};

    const IState = {
        valueOf() {
            return this._uid_;
        },
        equal(state) {
            return this.valueOf() === state.valueOf();
        },
        toProxy() {
            return cache[this._uid_];
        }
    };
    const STATE = {
        CURRENT: 'init',
        STATUS: utils.factory('Dictionary', function (state) { return state.hasOwnProperty('_uid_'); }),

        GET_CURRENT() {
            return this.STATUS.get(this.CURRENT);
        },
        INIT(target, state) {
            this.STATUS.set(this.CURRENT, state);
            target.State = new Proxy(this, {

            });
        },
        CHECKOUT(newState) {
            let curr = this.GET_CURRENT();
            this.STATUS.set(newState, JSON.parse(JSON.stringify(curr)));//不适合某些内置类型，如map，set
            this.CURRENT = newState;
        },
        DELETE(stateName) {
            if (stateName === this.CURRENT) return console.error('非法操作：当前状态' + stateName + "不允许删除");
            if (this.STATUS.has(stateName)) return this.STATUS.delete(stateName);
            console.error('目标不存在：状态' + stateName + "可能已删除");
        },
        UPDATE(state) {
            let curr = this.GET_CURRENT();
            Object.assign(curr, state);
        },
        SWITCH(stateName) {
            if (this.STATUS.has(stateName)) return this.CURRENT = stateName;
            console.error('目标不存在：状态' + stateName + "可能已删除");
        }
    };
    class State {

        constructor(state, el) {
            this.data = state;
            assistant.stateful(state);
            conference.convoke('render-el', { el, state: state });
        }
        addState(state, el) {
            assistant.stateful(state);
            conference.convoke('render-el', { el, state });
        }
    }

    const assistant = {
        isState(state) { return state.hasOwnProperty('_uid_') },
        stateful(target) {
            let uid = utils.grantUid(target);
            target.__proto__ = IState;
            cache[uid] = new Proxy(target, {
                get(o, p) {
                    let v = o[p];
                    // if(utils.isFunc(v)){
                    //     return function(...args){
                    //         return v(...args);
                    //     }
                    // }
                    if (utils.isObject(v)) return cache[v.valueOf()];
                    if (utils.isPrimitive(v)) {
                        //if (obj._uid_) throw obj;
                        //utils.grantUid(obj);
                        pub_sub.subscribe(globalThis, 'capture', {
                            see(prey) {
                                pub_sub.subscribe(uid, p, { see: prey });
                            }
                        });
                    }
                    return v;

                },
                set(o, p, v) {
                    let old = o[p];
                    if (old === v) return false;
                    o[p] = v;
                    let type = old == undefined ? 'create' : 'modify';
                    pub_sub.notify(uid, p, [v, old, type]);
                    return true;
                }
            });
            Object.values(target).forEach(v => {
                if (utils.isObject(v)) this.stateful(v);
            })

        },
        pathData(dataSource, path, delimiter = '.') {
            let data = dataSource;
            return path.split(delimiter).map(prop => {
                let obj = data;
                data = data[prop];
                //console.log(d, prop, data,);
                return [obj, prop, data];
            });
        },

        tokenize(strTmpl) {
            let n = 0;
            let str = "";
            let all = [];
            let vars = [];
            function push() {
                if (!str) return;
                let token = ['text', str];
                all.push(token);
                if (n > 0) {
                    token[0] = 'var';
                    vars.push(token);
                }
                str = "";
            }

            for (let i = 0; i < strTmpl.length; i++) {
                let char = strTmpl[i];
                if (!char) continue;
                if (char === '{') {
                    if (strTmpl[i + 1] === '{') {
                        ++i;
                        push();
                        ++n;
                        continue;
                    }
                }
                else if (char === '}' && n > 0) {
                    if (strTmpl[i + 1] === '}') {
                        ++i;
                        push();
                        --n;
                        continue;
                    }
                }
                str += char;
            }
            push();
            return all;
        },
        unTokenize(tokens, data) {
            return tokens.map(token => {
                let [type, path] = token;
                if (type != 'var') return path;
                let [obj, prop, val] = this.pathData(data, path).pop();
                if (utils.isFunc(val)) return val.call(data);
                return val;
            }).join('');
        },
    }

    const RENDER = {
        CACHE: {
            setAttribute(prop, val) {
                if (val === true) this.setAttribute(prop, "");
                else if (val === false) this.removeAttribute(prop);
                else this.setAttribute(prop, val);
            },
            TEXTreacter(scope, tokens) {
                this.textContent = assistant.unTokenize(tokens, scope);
            },
            ATTRsetAttribute(obj, prop, data, el) {
                pub_sub.subscribe(obj, prop, {
                    see: this.setAttribute.bind(el, prop)
                });
                pub_sub.notify(obj, prop, data);
            }
        },
        TEXT(el, scope) {
            let tokens = assistant.tokenize(el.textContent);
            this.CACHE.TEXTreacter.call(el, scope.toProxy(), tokens);
            pub_sub.notify(globalThis, 'capture', this.CACHE.TEXTreacter.bind(el, scope, tokens), true);
        },
        ATTR(el, scope) {
            let path = el.getAttribute(':attr');
            el.removeAttribute(':attr');
            let [obj, prop, data] = assistant.pathData(scope, path).pop();
            if (utils.isPrimitive(data)) {
                this.CACHE.ATTRsetAttribute(obj, prop, data, el);
            } else if (utils.isObject(data)) {
                Object.keys(data).forEach(key => {
                    this.CACHE.ATTRsetAttribute(data, key, data[key], el);
                });
            } else if (utils.isFunc(data)) {///待优化
                function reacter(scope) {
                    let val = data.call(scope);
                    if (val === true) this.setAttribute(prop, "");
                    else if (val === false) this.removeAttribute(prop);
                    else this.setAttribute(prop, val);
                };
                reacter.call(el, scope.toProxy());
                pub_sub.notify(globalThis, 'capture', reacter.bind(el, scope), true);
            }
        },
        IF(el, scope) {
            let path = el.getAttribute(':if');
            el.removeAttribute(':if');
            let [obj, prop, data] = assistant.pathData(scope, path).pop();
            const comment = document.createComment('');
            if (utils.isFunc(data)) {///待优化
                function reacter(scope) {
                    let val = data.call(scope);
                    if (val) comment.replaceWith(el);
                    else el.replaceWith(comment);
                };
                reacter.call(el, scope.toProxy());
                pub_sub.notify(globalThis, 'capture', reacter.bind(el, scope), true);
            }
            else {
                pub_sub.subscribe(obj, prop, {
                    see(val) {
                        if (val) comment.replaceWith(el);
                        else el.replaceWith(comment);
                    }
                });
                pub_sub.notify(obj, prop, data);
            };
        },
    }

    inject('State', State);
    const getElType = function () {
        if (this.nodeType === Node.TEXT_NODE && this.textContent.includes('{{')) return 'TEXT';
        if (this.nodeType === Node.ELEMENT_NODE && !['SCRIPT', 'STYLE'].includes(this.nodeName)) {
            if (this.hasAttribute(':vm')) return 'VM';
            if (this.hasAttribute(':for')) return 'FOR';
            if (this.hasAttribute(':if')) return 'IF';
            if (this.hasAttribute(':attr')) return 'ATTR';
            return 'EL'
        }
        return 'OTHER';
    };
    conference.create('render-el').add({
        say: async function (pipe) {
            let eT = getElType.call(pipe.el);
            if (eT === 'OTHER') return;
            if (eT !== 'TEXT') return await this.next.say(pipe, eT);
            let { el, state } = pipe;
            RENDER.TEXT(el, state);
        }
    }).add({
        say: async function (pipe, eT) {
            if (eT !== 'VM') return await this.next.say(pipe, eT);
            let { el } = pipe;
            let vm = el.vm || el.key('vm');
            await vm._ob_.notify(vm, 'render-vm', el);
        }
    }).add({
        say: async function (pipe, eT) {
            if (eT !== 'FOR') return await this.next.say(pipe, eT);
            let { el, state } = pipe;
            let path = el.getAttribute(':for');
            el.removeAttribute(':for');

            let [, , scope] = utils.pathData(state, path).pop();
            let taskArgs = Object.keys(scope).map(key => {
                let item = scope[key].toProxy();
                console.log(item);

                let data = {
                    toProxy() {
                        return {
                            $key: key,
                            $item: item,
                            __proto__: state.toProxy()
                        }
                    },
                    $key: key,
                    $item: scope[key],
                    __proto__: state,
                };

                let node = el.cloneNode(true);
                node.scope = data;
                el.before(node);
                return [node, data];
            });
            await Promise.all(taskArgs.map(async taskArg => {
                let [el, state] = taskArg;
                await conference.convoke('render-el', { el, state });
            }))
            el.remove();
        }
    }).add({
        say: async function (pipe, eT) {
            if (eT !== 'EL') eT = await this.next.say(pipe, eT);
            if (eT !== 'EL') return;
            let { el, state } = pipe;
            let vm = el.vm || el.key('vm');
            let tasks = [...el.childNodes].map(child => {
                return conference.convoke('render-el', { el: child, state });

            });
            let arr = await Promise.all(tasks);
            if (el === vm.el) {
                if (el === document.body) {
                    vm.trigger('vm-ready');
                }
                else {
                }
            }
        }

    }).add({
        say: async function (pipe, eT) {
            if (eT !== 'ATTR') eT = await this.next.say(pipe, eT);
            if (eT !== 'ATTR') return eT;
            let { el, state } = pipe;
            RENDER.ATTR(el, state);
            return getElType.call(pipe.el);
        }

    }).add({
        say: async function (pipe, eT) {
            if (eT !== 'IF') return eT;
            let { el, state } = pipe;
            RENDER.IF(el, state);
            return getElType.call(pipe.el);
        }
    })
})();

(function (global) {
    const [{ conference, utils }, extensions, State] = using(
        'core',
        'extensions',
        'State'
    );

    Object.assign(global, {
        /**
         * 创建一个指定名字的VM对象
         * @param {string} name
         * @param {object} set
         * @returns {iloview&{ready(onload:Function):void}}
         */
        createVm(name, set) {
            let iou = lvu;
            extensions.forEach(ext => { iou.addExtenssion(ext); });
            
            let vm = this[name] = iou.$$(document.body, set);

            vm.ready = function (onload) {
                function once(e) {
                    onload(vm, conference);
                    global.removeEventListener('vm-ready', once);
                }
                global.addEventListener('vm-ready', once)
                delete this.ready;
            };
            return vm;
        },
        /**
         * 创建一个指定名字为body的VM对象
         * @param {object} set
         */
        createDefaultVm(set) {
            return this.createVm('body', set);
        },
    });

    /**
    * @param {Element} el
    * @param {iloview} parentNode
    * @returns {iloview&ThisType<lvu>}
    */
    function iloview(el, parentNode) {
        this.el = el;
        el.vm = this;
        let observer = this._ob_ = utils.factory(ENUM.factoryService.发布订阅服务);
        this.parentNode = this.__proto__ = parentNode;

    };
    let lvu = iloview.prototype = {
        el: document,
        addExtenssion(obj) {
            lvu.__proto__ = obj;
            lvu = obj;
        },
        /**
         * 返回一个VM实例
         * @param {Element} el
         * @param {object} set
         * @returns {iloview} iloview实例
         */
        $$(el, set) {
            let vm = new iloview(el, this);            
            vm._ob_.subscribe(vm, 'render-vm', {
                see(el) {
                    let subVm = el.getAttribute(':vm');
                    el.removeAttribute(':vm');//终止循环
                    vm[subVm] = vm.$$(el, set[subVm] || {});
                }
            });
            vm.build(set);
            if (set.event) vm.listen(set.event,vm.state);
            return vm;
        },
        /**
         *
         * @param {object} set
         * @returns {iloview} iloview实例
         */
        build(set) {
            let Store = new State(set.state() || {},this.el);
            this.state = Store.data.toProxy();
            return this;
        },
        /**
         * ...
         * @this {iloview}
         * @param {Element} el
         */
        render: async function (el, state) {
            conference.convoke('render-el', { el, state });
        },
    };



})(globalThis)